﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using snat.algorithms;
using snat.model;
using snat.util;
using System.IO;

namespace algorithms.Algorithms.MessageRates {
    public class ClusterMessageRates 
        : IAlgorithm, IChartRenderable, IReaderWriter {

            private TimeSpan intervalSpan;
            private DateTime currentInterval;

            public Dictionary<int, Dictionary<DateTime, int>> Rate { get; private set; }
            public Dictionary<int, int> Count { get; private set; }

            private List<int> clusters = new List<int>();

            public string Name {
                get { return "Cluster-Based Message Rates"; }
            }

            public ClusterMessageRates(TimeSpan _interval) {
                this.intervalSpan = _interval;
            }

            public void OnTapeLoaded() {
                foreach (ClusterNode n in NetworkModel.Instance.Nodes.Values) {
                    clusters.Add(n.ClusterID);
                }
                clusters = clusters.Distinct<int>().ToList();
                this.Rate = clusters.ToDictionary<int, int, Dictionary<DateTime, int>>(
                        k => k, v => new Dictionary<DateTime, int>());
                this.Count = clusters.ToDictionary<int, int, int>(
                        k => k, v => 0);
                currentInterval = NetworkModel.Instance.StartTime;
                foreach (int clusterID in clusters) {
                    Rate[clusterID].Add(currentInterval, 0);
                }
            }

            public void OnMessageSend(Message m, BaseNode n) {
                Count[(n as ClusterNode).ClusterID]++;
                while (m.Timestamp >= currentInterval + intervalSpan) {
                    currentInterval += intervalSpan;
                    foreach (int clusterID in clusters) {
                        Rate[clusterID].Add(currentInterval, 0);
                    }
                }
                Rate[(n as ClusterNode).ClusterID][currentInterval] += m.Recipients.Count;
            }

            public void OnMessageProcessed(Message m) {

            }

            public void Output() {
                if (RenderChart != null) RenderChart(this);
            }

            public void Register() {
                NetworkModel.Instance.TapeLoaded += OnTapeLoaded;
                NetworkModel.Instance.MessageProcessed += OnMessageProcessed;
                foreach (BaseNode n in NetworkModel.Instance.Nodes.Values) {
                    n.MessageSend += OnMessageSend;
                }
                NetworkModel.Instance.TapePaused += Process;
                NetworkModel.Instance.TapeEnded += Process;
            }

            private void Process() {
                if (RenderChart != null) RenderChart(this);
            }

            public void DeRegister() {
                NetworkModel.Instance.TapeLoaded -= OnTapeLoaded;
                foreach (BaseNode n in NetworkModel.Instance.Nodes.Values) {
                    n.MessageSend -= OnMessageSend;
                }
                NetworkModel.Instance.MessageProcessed -= OnMessageProcessed;
                NetworkModel.Instance.TapePaused -= Process;
                NetworkModel.Instance.TapeEnded -= Process;
            }

            public event RenderChartDelegate RenderChart;

            public snat.util.DataChart GetRenderableChart() {
                return null;
            }

            public void Write(string filePath) {
                using (StreamWriter output = new StreamWriter(filePath)) {
                    foreach (int n in Rate.Keys) {
                        output.WriteLine("{0} :::", n);
                        foreach (DateTime t in Rate[n].Keys) {
                            output.WriteLine("\t{0}, {1}", t.ToShortDateString(), Rate[n][t]);
                        }
                    }
                }
            }

            public void WriteToDir(string dirPath) {
                DirectoryInfo d = new DirectoryInfo(dirPath);
                if (!d.Exists) d.Create();
                foreach (int n in Rate.Keys) {
                    using (StreamWriter output = new StreamWriter(String.Join("\\", dirPath, n+".csv"))) {
                        foreach (DateTime t in Rate[n].Keys) {
                            output.WriteLine("{0}, {1}", t.ToShortDateString(), Rate[n][t]);
                        }
                    }
                }
            }

            public string Read(string filePath) {
                StringBuilder ret = new StringBuilder();
                using (StreamReader input = new StreamReader(filePath)) {
                    while (!input.EndOfStream) {
                        ret.Append(input.ReadLine());
                    }
                }
                return ret.ToString();
            }
        }

    }

